-----------Addition Magician-----------
A 4am crack                  2016-01-28
---------------------------------------

Name: Addition Magician
Genre: educational
Year: 1984
Author: Dale Disharoon
Publisher: The Learning Company
Media: single-sided 5.25-inch floppy
OS: custom
Previous cracks: none
Similar cracks:
  #476 Microzine 2
  #464 Microzine 4
  #409 Microzine 5
  #332 Microzine 3

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  immediate disk read error

Locksmith Fast Disk Backup
  unable to read any track

EDD 4 bit copy (no sync, no count)
  read errors on T11+
  copy displays a graphical title page
    then hangs with the drive motor on

Copy ][+ nibble editor
  T00 -> standard prologues, modified
    epilogues (FF FF FF)
  T01,02 -> corrupted address fields
    that claim to be track $00
  T03,04 -> not full tracks? looks
    like they have some standard-ish
    sectors, but not 16 per track
    (also corrupted address fields)
  T05-T0C -> more corrupted address
    fields (like T01)
  T0D-T10 -> uncorrupted address fields
    but still non-standard epilogues
  T11+ unformatted

When I say "corrupted address fields,"
this is what that looks like:

                 --v--

   COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------

TRACK: 01  START: 21DC  LENGTH: 189D
       ^^

21B8: FF FF FF FF FF FF FF FF   VIEW
21C0: FF FF FF FF FF FF FF FF
21C8: FF FF FF FF FF FF FF FF
21D0: FF FF FF FF FF FF FF FF
21D8: FF FF FF FF FF D5 AA 96  <-21DD
                     ^^^^^^^^
                 address prologue

21E0: AA AA AA AA AA AA AA AA
      ^^^^^ ^^^^^ ^^^^^ ^^^^^
      V000   T00   S00  chksm

21E8: FF FF FF FF FF CF F3 FC
      ^^^^^^^^
  address epilogue

21F0: FF FF D5 AA AD 9B DB B9
            ^^^^^^^^
         data prologue

21F8: B9 DB F2 DE B9 AE B3 BA

---------------------------------------

  A  TO ANALYZE DATA  ESC TO QUIT

  ?  FOR HELP SCREEN  /  CHANGE PARMS

  Q  FOR NEXT TRACK   SPACE TO RE-READ

                 --^--

The disk is lying to me. The address
field claims to be track $00, but it's
really track $01. Bad disk! Stop lying!

Disk Fixer
  ["O" -> "Input/Output Control"]
    set Address Epilogue to "FF FF FF"
    set Data Epilogue to "FF FF FF"
  T00 readable
  T01-T0C unreadable (no option to
    ignore the corrupted address field)
  T0D-T10 readable
  T11+ unreadable (unformatted)

Copy ][+ sector editor
  ["P" -> "Sector Editor Patcher"]
    set type to "CUSTOM"
    set Address Epilogue to "FF FF"
    set Data Epilogue to "FF FF FF"
  T00 readable
  T0D-T10 readable

  ["P" -> "Sector Editor Patcher"]
    set CHECK TRACK to "NO"
  T01 readable!
  only parts of T02 and T03 readable:
    T02: S03,04,05,06,07,0A,0B,0C,0D,0E
    T03: S01,02,08,09,0F
  T04-T0C readable!

Why didn't COPYA work?
  modified epilogue bytes on track $00

Why didn't Locksmith FDB work?
  ditto

Why didn't my EDD copy work?
  I've seen similar disks, where the
  first N tracks have intentionally
  corrupted address fields. (N varies
  from disk to disk.) There's a custom
  loader that loads the data from those
  corrupted tracks, then transfers
  control to a standard RWTS for the
  rest of the program. Somewhere in the
  corrupted tracks, it will load data
  from consecutive half tracks. (These
  are devilishly difficult to copy, and
  I didn't even try.) That's just an
  educated guess; I could be surprised.

Hey, I can actually validate that guess
in the Copy ][+ nibble editor, which
can read half tracks.

                 --v--

   COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------

TRACK: 02.50  START: 3700  LENGTH: 198E
       ^^^^^

3BD0: FF FF FF FF FF FF FF FF   VIEW
3BD8: FF FF FF FF FF FF FF FF
3BE0: FF FF FF FF FF FF FF FF
3BE8: FF FF C9 FF FF FF FF FF
3BF0: FF FF FF FF FF D5 AA 96  <-3BF5
                     ^^^^^^^^
                  address prologue

3BF8: AA AA AA AA AF AB AF AB
      ^^^^^ ^^^^^ ^^^^^ ^^^^^
      V000   T00   S0B  chksm

3C00: FF FF FF 9F E7 F9 FE FF
      ^^^^^^^^
  address eplogue

3C08: D5 AA AD A7 B4 BD CD ED
      ^^^^^^^^
   data prologue

3C10: ED 9B ED F2 E9 DF B6 AB

---------------------------------------

  A  TO ANALYZE DATA  ESC TO QUIT

  ?  FOR HELP SCREEN  /  CHANGE PARMS

  Q  FOR NEXT TRACK   SPACE TO RE-READ

                 --^--

Jackpot! (Note that it's still claiming
to be track $00, though, just like the
other whole tracks above and below it.)

Next steps:

  1. Trace the boot
  2. ???

                   ~

               Chapter 1
         Boot Trace and Chill


[S6,D1=original disk]
[S5,D1=my work disk]

]PR#5
CAPTURING BOOT0
...reboots slot 6...
...reboots slot 5...
SAVING BOOT0

]CALL -151

*800<2800.28FFM

*801L

; set reset vector
0801-   8A          TXA
0802-   4A          LSR
0803-   4A          LSR
0804-   4A          LSR
0805-   4A          LSR
0806-   09 C0       ORA   #$C0
0808-   85 3F       STA   $3F
080A-   8D F3 03    STA   $03F3
080D-   49 A5       EOR   #$A5
080F-   8D F4 03    STA   $03F4
0812-   A9 00       LDA   #$00
0814-   8D F2 03    STA   $03F2

; hmm
0817-   A9 04       LDA   #$04
0819-   48          PHA

; machine initialization (memory banks,
; TEXT, IN#0, PR#0, &c.)
081A-   8D 81 C0    STA   $C081
081D-   20 2F FB    JSR   $FB2F
0820-   8D 52 C0    STA   $C052
0823-   20 89 FE    JSR   $FE89
0826-   20 93 FE    JSR   $FE93

; clear hi-res screen 1
0829-   A2 20       LDX   #$20
082B-   A0 00       LDY   #$00
082D-   84 06       STY   $06
082F-   A9 20       LDA   #$20
0831-   85 07       STA   $07
0833-   98          TYA
0834-   91 06       STA   ($06),Y
0836-   C8          INY
0837-   D0 FB       BNE   $0834
0839-   E6 07       INC   $07
083B-   CA          DEX
083C-   D0 F6       BNE   $0834

; switch to hi-res screen 1 (blank)
083E-   8D 57 C0    STA   $C057
0841-   8D 50 C0    STA   $C050
0844-   8D 54 C0    STA   $C054
0847-   8D 52 C0    STA   $C052

; set up ($3E) vector to point to the
; sector read routine in the disk
; controller ROM
084A-   A9 5C       LDA   #$5C
084C-   85 3E       STA   $3E

; the disk controller ROM always exits
; via $0801, so set that to an RTS so
; we can JSR and not have to set up a
; loop
084E-   A9 60       LDA   #$60
0850-   8D 01 08    STA   $0801

; hmm
0853-   A9 72       LDA   #$72
0855-   48          PHA

OK, we've now pushed $04/$72 on the
stack. That's probably important.

; multi-sector read
; Y = first logical sector ($01)
; X = last logical sector ($0E)
; A = start address high byte ($09)
0856-   A0 00       LDY   #$00
0858-   84 FC       STY   $FC
085A-   C8          INY
085B-   A9 09       LDA   #$09
085D-   A2 0E       LDX   #$0E

; call multi-sector read routine
085F-   20 65 08    JSR   $0865

; another sector read, this time just
; one sector, into $0400 (X is already
; less than Y on entry, so loop will
; exit after one read)
0862-   A9 04       LDA   #$04
0864-   AA          TAX

; falls through to multi-sector read
; entry point (was also called earlier)
0865-   85 27       STA   $27
0867-   E8          INX
0868-   86 49       STX   $49
086A-   84 F9       STY   $F9

; map logical into physical sector and
; store it in zero page where the disk
; controller ROM will look for it
086C-   B9 83 08    LDA   $0883,Y
086F-   85 3D       STA   $3D

; read sector via disk controller ROM
0871-   20 7E 08    JSR   $087E

; loop until done
0874-   A4 F9       LDY   $F9
0876-   C8          INY
0877-   C4 49       CPY   $49
0879-   90 EF       BCC   $086A
087B-   A5 27       LDA   $27

; subroutine to read a sector via ($3E)
; which points to $Cx5C, which exits
; via $0801, which is now an "RTS"
; (HOW F---ING ELEGANT IS THAT, RIGHT?)
0885-   A6 2B       LDX   $2B
0887-   6C 3E 00    JMP   ($003E)

; physical to logical sector map
0883- 00 03 05 07 09
0888- 0B 0D 0F 02 04 06 08 0A
0890- 0C 0E 01

That's it. Flexible but compact.

It's a weird combination of reads,
though. It loads a bunch of sectors at
$0900, then the last one at $0400.
That's part of the text page, but it's
hidden during boot because we cleared
the entire hi-res graphics page and
showed that instead.

Of course, we manually pushed $04/$72
on the stack earlier, so once we fall
through to the sector read routine,
reads the last sector, and hits the RTS
we put at $0801, it will "return" to
$0472 + 1 = $0473.

Let's interrupt the boot before it gets
there.

                   ~

               Chapter 2
 In Which Things Get Brilliantly Weird


*9600<C600.C6FFM

; set up callback by changing the two
; bytes that are pushed to the stack
96F8-   A9 97       LDA   #$97
96FA-   8D 18 08    STA   $0818
96FD-   A9 04       LDA   #$04
96FF-   8D 54 08    STA   $0854

; start the boot
9702-   4C 01 08    JMP   $0801

; callback is here --
; copy $0400 up to higher memory so it
; survives a reboot
9705-   A0 00       LDY   #$00
9707-   B9 00 04    LDA   $0400,Y
970A-   99 00 24    STA   $2400,Y
970D-   C8          INY
970E-   D0 F7       BNE   $9707

; turn off slot 6 drive motor
9710-   AD E8 C0    LDA   $C0E8

; reboot to my work disk
9713-   4C 00 C5    JMP   $C500

*BSAVE TRACE,A$9600,L$116

*BRUN TRACE
...reboots slot 6...
...reboots slot 5...

]BSAVE BOOT1 0400-04FF,A$2400,L$100
]CALL -151

The entry point was $0473, so let's
start there. I'll have to leave the
code at $2400. Relative branches will
look correct, but absolute addresses
in $04xx will be +$2000.

*2473L

; zp$4A is important later (see below)
2473-   46 4A       LSR   $4A
2475-   20 33 04    JSR   $0433

*2433L

; call the following line (then fall
; through and do it again)
2433-   20 36 04    JSR   $0436

; save A and Y
2436-   48          PHA
2437-   98          TYA
2438-   48          PHA

; low-level disk stuff (see below)
2439-   A5 FC       LDA   $FC
243B-   85 FD       STA   $FD
243D-   E6 FC       INC   $FC
243F-   A5 FC       LDA   $FC
2441-   29 03       AND   #$03
2443-   0A          ASL
2444-   05 2B       ORA   $2B
2446-   A8          TAY
2447-   B9 81 C0    LDA   $C081,Y

; wait loop
244A-   A9 30       LDA   #$30
244C-   20 A8 FC    JSR   $FCA8

; more low-level disk stuff
244F-   A5 FD       LDA   $FD
2451-   29 03       AND   #$03
2453-   0A          ASL
2454-   05 2B       ORA   $2B
2456-   A8          TAY
2457-   B9 80 C0    LDA   $C080,Y

; more waiting
245A-   A9 30       LDA   #$30
245C-   20 A8 FC    JSR   $FCA8

; restore A and Y on the way out
245F-   68          PLA
2460-   A8          TAY
2461-   68          PLA
2462-   60          RTS

This is a very clever and compact way
to advance the drive head to the next
track. Normally DOS 3.3 keeps track of
this and has a (much more complicated)
routine to move the head back and forth
as needed. But this loader only needs
to move it forward, so the entire
process collapses to this:

1. Set up the Y register to be a slot
   number (x16) plus the appropriate
   phase (0-3, depending on which track
   the drive head is on)

2. LDA $C081,Y to turn on the
   appropriate stepper motor

3. Wait exactly the right amount of
   time (as measured in CPU cycles)

4. LDA $C080,Y to turn off the
   appropriate stepper motor

5. Wait the right amount of time again

...which is exactly what this routine
at $0436 is doing. But that only gets
us halfway there -- literally, it only
moves the drive head by half a track.
But! Since $0433 "falls through" to
$0436, it ends up doing this twice. Two
half tracks equal one whole track, so
calling the routine at $0433 will move
the drive head to the next whole track.

(By the way, this is why it initialized
zero page $FC to $00 at $0858. That's
the "current" track where the drive
head is at boot; it gets updated when
the drive head advances.)

Everything I know about low-level disk
stepping, I learned from this excellent
Usenet post:
macgui.com/usenet/?group=1&id=31160

Continuing...

; multi-sector read, similar to the one
; we did in boot0
; Y = first logical sector (unset, but
;     the entry point we're calling
;     sets it to $00)
; X = last logical sector ($08)
; A = start address high byte ($17)
2478-   A9 17       LDA   #$17
247A-   A2 08       LDX   #$08
247C-   20 13 04    JSR   $0413

*2413L

; first logical sector
2413-   A0 00       LDY   #$00

; store A in zero page $27, used by the
; disk controller ROM routine as the
; target page to store sectors read
; from disk
2415-   85 27       STA   $27

; X is the final sector to read
2417-   E8          INX
2418-   86 49       STX   $49

; Y is the current sector to read
; (starting with whatever was passed in
; and incrementing until it equals the
; value passed in the X register)
241A-   84 F9       STY   $F9
241C-   98          TYA

; But wait, there's more! Based on the
; high bit of zero page $4A, Y is
; either a logical sector (the map of
; logical->physical sectors is at
; $0463) or a physical sector
241D-   24 4A       BIT   $4A
241F-   30 03       BMI   $2424
2421-   B9 63 04    LDA   $0463,Y

; store physical sector in $3D (again,
; used by the disk controller ROM)
2424-   85 3D       STA   $3D

; read sector by jumping to ($003E),
; which points to $Cx5C (e.g. $C65C if
; booting from slot 6) and exit via
; $0801, which is an RTS by now, so
; this just continues to the next line
2426-   20 00 04    JSR   $0400

; increment sector index
2429-   A4 F9       LDY   $F9
242B-   C8          INY

; are there more sectors to read?
242C-   C4 49       CPY   $49

; yes, branch back and repeat
242E-   90 EA       BCC   $241A

; no, exit with last page (+1) in A
; (disk controller ROM increments this
; after storing sector data, so on exit
; this will be the first page that was
; NOT filled with data in this loop)
2430-   A5 27       LDA   $27
2432-   60          RTS

And that's how we fill up $0800..$1FFF:
$0900..$16FF were read from track $00
(at $0856), now $1700..$1FFF are read
from track $01.

; now call the code we just loaded
247F-   20 00 09    JSR   $0900
2482-   20 00 1F    JSR   $1F00

That's where I need to interrupt the
boot.

                   ~

               Chapter 3
 In Which Things Get Weirdly Brilliant


*9600<C600.C6FFM

; set up callback #1 and start the boot
96F8-   A9 97       LDA   #$97
96FA-   8D 18 08    STA   $0818
96FD-   A9 04       LDA   #$04
96FF-   8D 54 08    STA   $0854
9702-   4C 01 08    JMP   $0801

; callback #1 is here --
; set up callback #2 after we load
; $0800..$1FFF
9705-   A9 4C       LDA   #$4C
9707-   8D 7F 04    STA   $047F
970A-   A9 17       LDA   #$17
970C-   8D 80 04    STA   $0480
970F-   A9 97       LDA   #$97
9711-   8D 81 04    STA   $0481

; continue the boot
9714-   4C 73 04    JMP   $0473

; callback #2 is here --
; copy everything to graphics page so
; it doesn't get overwritten by the
; HELLO program on my work disk
9717-   A2 18       LDX   #$18
9719-   A0 00       LDY   #$00
971B-   B9 00 08    LDA   $0800,Y
971E-   99 00 28    STA   $2800,Y
9721-   C8          INY
9722-   D0 F7       BNE   $971B
9724-   EE 1D 97    INC   $971D
9727-   EE 20 97    INC   $9720
972A-   CA          DEX
972B-   D0 EE       BNE   $971B

; turn off the slot 6 drive motor and
; reboot to my work disk
972D-   AD E8 C0    LDA   $C0E8
9730-   4C 00 C5    JMP   $C500

*BSAVE TRACE2,A$9600,L$133
*9600G
...reboots slot 6...
...reboots slot 5...

]BSAVE BOOT1 0800-1FFF,A$2800,L$1800
]CALL -151

*800<2800.3FFFM
*900G
...displays graphical title screen...

This appears to be some sort of hi-res
unpacker. It is self-contained, does no
disk access, and returns gracefully to
the monitor when it completes.

The other call to $1F00 (at $0482) is a
check for Applesoft BASIC in ROM. If it
is not present (very old machine!), it
prints "REQUIRES APPLESOFT..." and
hangs.

Continuing, then, from $0485...

*BLOAD BOOT1 0400-04FF,A$2400
*2485L

2485-   20 CA 04    JSR   $04CA

*24CAL

; advance the drive head a whole track
24CA-   20 33 04    JSR   $0433

[now on track 2]

; zero page fiddling (see below)
24CD-   A9 00       LDA   #$00
24CF-   85 41       STA   $41
24D1-   38          SEC
24D2-   66 4A       ROR   $4A

; Read several sectors (but not the
; entire track)
; A = start address high byte ($08)
; Y = first sector ($01)
; X = last sector ($05)
24D4-   A9 08       LDA   #$08
24D6-   A0 01       LDY   #$01
24D8-   A2 05       LDX   #$05
24DA-   20 15 04    JSR   $0415

; move the drive head one phase only,
; to the next HALF track
24DD-   20 36 04    JSR   $0436

[now on track 2.5]

; read more sectors ($06..$0A)
24E0-   A2 0A       LDX   #$0A
24E2-   20 15 04    JSR   $0415

; advance another half track
24E5-   20 36 04    JSR   $0436

[now on track 3]

; read more sectors ($0B..$0F)
24E8-   A2 0F       LDX   #$0F
24EA-   20 15 04    JSR   $0415

; fiddle with $4A again
24ED-   46 4A       LSR   $4A
24EF-   60          RTS

So here's the deal with $4A: we
initialized it at $0473 by a blind LSR,
which clears the high bit. This tells
the multi-sector read routine at $0415
to use logical sectors. Then we set the
high bit at $04D1 with SEC + ROR,
indicating we want $0415 to read
physical sectors. Then we read a few
sectors from track 2, a few from track
2.5, and a few from track 3. Then we
reset $4A with another LSR, and we're
back to using logical sectors.

This explains why my EDD bit copy
failed. This disk is storing data on
half tracks. Worse, it's storing data
on *adjacent* half tracks -- a few from
track 2, a few from track 2.5, and a
few from track 3. Due to limitations of
the Disk II drive mechanism, that would
be virtually impossible for a generic
bit copier to reproduce on a blank
floppy disk.

Every part of this code is brilliant,
AND it fits in a single sector on the
text page, AND it's flexible enough to
read from virtually uncopyable disks.

                   ~

               Chapter 4
         Every Byte Is Sacred,
         Every Byte Is Great,
         If A Byte Gets Wasted,
         Woz Gets Quite Irate


Continuing from $0488...

*2488L

; move to next whole track
2488-   20 33 04    JSR   $0433

[now on track 4]

; read several sectors into $1700+
248B-   A9 17       LDA   #$17
248D-   A2 08       LDX   #$08
248F-   20 13 04    JSR   $0413

We have now re-filled $0800..$1FFF.

2492-   A9 40       LDA   #$40
2494-   20 05 04    JSR   $0405
2497-   20 05 04    JSR   $0405

This is very interesting. $0405 looks
like this:

*2405L

2405-   20 0E 04    JSR   $040E
2408-   20 0E 04    JSR   $040E
240B-   20 0E 04    JSR   $040E
240E-   20 33 04    JSR   $0433
2411-   A2 0F       LDX   #$0F
2413-   A0 00       LDY   #$00
2415-   85 27       STA   $27
.
. multi-sector read routine (see above)
.

$0411 sets X and Y to read an entire
track (sector $00 through $0F). Before
that, $040E advances to the next whole
track. And before *that*, we have three
identical JSRs to $040E, each of which
falls through to the next, and
eventually to $040E again.

Thus, calling $040E will advance one
whole track and read one whole track.
Calling $040B will do that twice,
reading each track into consecutive
memory (because the multi-sector read
routine ends with next page in memory
in the accumulator, so you can chain
them and just fill up memory without
having to reset the starting page).

Calling $0408 will do it three times,
and calling $0405 will do it four times
(again, into consecutive memory). So
these three lines of code...

2492-   A9 40       LDA   #$40
2494-   20 05 04    JSR   $0405
2497-   20 05 04    JSR   $0405

...will read tracks $05 through $0C
into $4000..$BFFF.

Other than hi-res page 1 ($2000-$3FFF),
which is currently showing the title
screen, we've just filled all of main
memory from $0800..$BFFF.

; move a chunk of code down to page 3
249A-   A0 6F       LDY   #$6F
249C-   B9 00 AF    LDA   $AF00,Y
249F-   99 00 03    STA   $0300,Y
24A2-   88          DEY
24A3-   10 F7       BPL   $249C

; now put slot number (x16) into...
; an RWTS parameter table?!?
24A5-   A6 2B       LDX   $2B
24A7-   8E E9 B7    STX   $B7E9

; turn off drive motor
24AA-   BD 88 C0    LDA   $C088,X

; set up DOS globals (tracking where
; the drive head is)
24AD-   20 8E BE    JSR   $BE8E
24B0-   A5 FC       LDA   $FC
24B2-   99 78 04    STA   $0478,Y
24B5-   4A          LSR
24B6-   8D 78 04    STA   $0478

; push $DFFF to the stack
24B9-   A9 DF       LDA   #$DF
24BB-   48          PHA
24BC-   A9 FF       LDA   #$FF
24BE-   48          PHA

; set up input routine to jump to
; the game code
24BF-   A9 00       LDA   #$00
24C1-   85 38       STA   $38
24C3-   A9 B6       LDA   #$B6
24C5-   85 39       STA   $39

; and exit via HOME (which will wipe
; this bootloader from memory)
24C7-   4C 58 FC    JMP   $FC58

Based on the initialization code here,
We appear to be loading a DOS 3.3
shaped RWTS. I suspect this will be
used to access the disk (those "normal"
tracks $0D-$10) during the game. Also,
the game is initializing Applesoft
BASIC. After the HOME routine at $FC58
returns, it will jump to $E000, because
we pushed $DFFF to the stack at $04B9.
Then it will try to print a prompt, but
the custom output vector at ($38) will
jump to the start of the game code at
$B600 instead.

So twisty.

                   ~

               Chapter 5
       In Which We See The Light
       At The End Of The Tunnel,
       And It's A DOS-shaped RWTS
       Which Is A Weird Thing To
       See In A Tunnel, Honestly


I can interrupt the boot at $049A to
capture whatever was read from tracks
2/2.5/3 and $04-$0C. Basically all of
main memory.

*9600<C600.C6FFM

; set up callback #1 and start the boot
96F8-   A9 97       LDA   #$97
96FA-   8D 18 08    STA   $0818
96FD-   A9 04       LDA   #$04
96FF-   8D 54 08    STA   $0854
9702-   4C 01 08    JMP   $0801

; callback #1 is here --
; put an unconditional monitor jump at
; $049A after we've loaded everything
; from tracks 2/2.5/3 and $04-$0C
9705-   A9 4C       LDA   #$4C
9707-   8D 9A 04    STA   $049A
970A-   A9 59       LDA   #$59
970C-   8D 9B 04    STA   $049B
970F-   A9 FF       LDA   #$FF
9711-   8D 9C 04    STA   $049C

; continue the boot
9714-   4C 73 04    JMP   $0473

*BSAVE TRACE3,A$9600,L$117
*9600G
...reboots slot 6...
<beep>

*C0E8
*2800<800.1FFFM
*C500G
...

]BSAVE BOOT2 0800-1FFF,A$2800,L$1800

After several more cycles of TRACE3, I
have all of main memory spread across
several files:

]CATALOG

C1983 DSR^C#254
206 FREE

 A 019 HELLO
 B 005 AUTOTRACE
 B 065 SUPER DEMUFFIN
 B 003 BOOT0
 B 003 TRACE
 B 003 BOOT1 0400-04FF
 B 003 TRACE2
 B 026 BOOT1 0800-1FFF
 B 003 TRACE3
 B 026 BOOT2 0800-1FFF
 B 034 BOOT2 4000-5FFF
 B 066 BOOT2 6000-9FFF
 B 034 BOOT2 A000-BFFF

One more thing...

]BLOAD BOOT2 A000-BFFF,A$2000,L$2000
]CALL -151

*3800L
.
. appears to be a DOS-shaped RWTS
.
3898-   A6 27       LDX   $27
389A-   20 BB B8    JSR   $B8BB
389D-   A9 FF       LDA   #$FF
389F-   20 B8 B8    JSR   $B8B8
38A2-   A9 FF       LDA   #$FF
38A4-   20 B8 B8    JSR   $B8B8
38A7-   A9 EB       LDA   #$EB
...

Confirmed: after the bootloader exits,
we have a full DOS 3.3 RWTS in memory.
Spot checking the RWTS, it's perfectly
normal except it expects "FF FF FF"
epilogue bytes. Which, by the way, is
just the sort of RWTS that could read
tracks $0D-$10.

I'll need to patch it to read the
standard epilogue instead.

*389E:DE
*38A3:AA
*3935:DE
*393F:AA
*3991:DE
*399B:AA
*3CAE:DE
*3CB3:AA
*BSAVE RWTS FIXED,A$3800,L$800

                   ~

               Chapter 6
     In Which Everything Is Simple
    If You Look At It The Right Way


Using Super Demuffin (with epilogues
"FF FF FF"), I "copied" the original
disk to a freshly formatted blank
disk. Of course, this only got track
$00 and tracks $0D-$10, but I'll take
it.

                 --v--

     LOCKSMITH 7.0  FAST DISK BACKUP


   R.************....******************
   W***********************************
HEX 00000000000000001111111111111111222
TRK 0123456789ABCDEF0123456789ABCDEF012
   0.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   1.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   2.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   3.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   4.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   5.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   6.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   7.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   8.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   9.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   A.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   B.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   C.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   D.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
12 E.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
   F.AAAAAAAAAAAA....AAAAAAAAAAAAAAAAAA
[               ] PRESS [RESET] TO EXIT

                 --^--

Now I need to write everything that I
captured from the corrupted tracks back
to tracks $01-$0C

Disk layout comparison:

track | old address | new address | sec
------+-------------+-------------+----
 $01  |        $1700-$1FFF        | 0-8
 $02  | $0800-$0CFF | $0800-$16FF | 0-E
$02.5 | $0D00-$11FF |             |
 $03  | $1200-$16FF |             |
 $04  |        $1700-$1FFF        | 0-8
 $05  |        $4000-$4FFF        | 0-F
 $06  |        $5000-$5FFF        | 0-F
 $07  |        $6000-$6FFF        | 0-F
 $08  |        $7000-$7FFF        | 0-F
 $09  |        $8000-$8FFF        | 0-F
 $0A  |        $9000-$9FFF        | 0-F
 $0B  |        $A000-$AFFF        | 0-F
 $0C  |        $B000-$BFFF        | 0-F

Of course, all the tracks will now have
normal address fields (no more lying
about the track numbers). Also no half
tracks and no spirals. Just, you know,
sectors on a disk. All the spiral track
stuff collapses into track $02, then
track $03 is completely unused.

[S6,D1=demuffin'd copy (T00, T0D-T10)]
[S5,D1=my work disk]

]PR#5
...
]CALL -151

*300L

; page count (decremented)
0300-   A9 30       LDA   #$09
0302-   85 FF       STA   $FF

; logical sector (incremented)
0304-   A9 00       LDA   #$00
0306-   85 FE       STA   $FE

; call RWTS to write sector
0308-   A9 03       LDA   #$03
030A-   A0 88       LDY   #$88
030C-   20 D9 03    JSR   $03D9

; increment logical sector, wrap around
; from $0F to $00 and increment track
030F-   E6 FE       INC   $FE
0311-   A4 FE       LDY   $FE
0313-   C0 10       CPY   #$10
0315-   D0 07       BNE   $031E
0317-   A0 00       LDY   #$00
0319-   84 FE       STY   $FE
031B-   EE 8C 03    INC   $038C

; Convert to the interleave order that
; this disk expects
031E-   B9 40 03    LDA   $0340,Y
0321-   8D 8D 03    STA   $038D

; increment page to write
0324-   EE 91 03    INC   $0391
0327-   C6 FF       DEC   $FF

; loop until done with all pages
0329-   D0 DD       BNE   $0308
032B-   60          RTS

; sector interleave table
*340.34F

0340- 00 06 05 04 03 02 01 0F
0348- 0E 0D 0C 0B 0A 09 08 07

; RWTS parameter table, pre-initialized
; with slot 6, drive 1, track $01,
; sector $00, address $1700, and RWTS
; write command ($02)
*388.397

0388- 01 60 01 00 01 00 FB F7
0390- 00 17 00 00 02 00 00 60

*BSAVE WRITE T01,A$300,L$98
*BLOAD BOOT1 0800-1FFF,A$800
*300G
...write write write...

Track 1 complete.

*301:0F       ; sector count
*38C:02       ; track
*391:08       ; first memory page
*BSAVE WRITE T02,A$300,L$98
*BLOAD BOOT2 0800-1FFF,A$800
*300G
...write write write...

Track 2 complete.

*301:09       ; sector count
*38C:04       ; track
*391:17       ; first memory page
*BSAVE WRITE T04,A$300,L$98
*300G
...write write write...

Track 4 complete.

*301:80       ; sector count
*38C:05       ; first track
*391:10       ; first memory page
*BSAVE WRITE T05+,A$300,L$98
*BLOAD BOOT2 4000-5FFF,A$1000
*BLOAD BOOT2 6000-9FFF,A$3000
*BLOAD BOOT2 A000-BFFF,A$7000
*BLOAD RWTS FIXED,A$8800
*300G
...write write write...

Tracks $05-$0C complete.

Now I need to modify the bootloader at
$0473 slightly.

  1. Modify the routine at $04CA to
     read 15 ($0E) sectors from track
     $02 instead of the spiral tracks,
     then skip track $03 altogether.

  2. Modify the routine at $0433 (that
     advances the drive head) so it
     updates zero page $41 with the
     current track.

The sector read routine at $C65C
compares the track listed in the
address field to zero page $41 and
loops forever until it matches. $C600
initializes $41 to 0, and the original
disk never updates $41, but everything
works because the address fields are
corrupted and all claim to be track 0.

So part of it will be simpler, because
we'll no longer be spiraling between
tracks. But part of it will actually
be more complicated because the address
fields are no longer corrupted and we
need to track the track number.

First, the patch at $04CA to load 15
($0E) sectors from track $02, then
skip over track $03.

T00,S07,$CA change to
20 33 04 A9 08 A2 0E 20 13 04 4C 33 04

which looks like this (using Disk
Fixer's built-in disassembler):

                 --v--

00CA:20 33 04       JSR   $0433
00CD:A9 08          LDA   #$08
00CF:A2 0E          LDX   #$0E
00D1:20 13 04       JSR   $0413
00D4:4C 33 04       JMP   $0433

                 --^--

Second, a new routine at $04D7 (now
unused space) to increment the track
number in zero page.

T00,S07,$D7 change to "E6 41 4C 36 04"

                 --v--

00D7:E6 41          INC   $41
00D9:4C 36 04       JMP   $0436

                 --^--

Third, the patch at $0433 to call the
new routine at $04D7 so we increment
the track number in zero page before
advancing the drive arm.

T00,S07,$34 change "36" to "D7"

                 --v--

0033:20 D7 04       JSR   $04D7

                 --^--

]PR#6
...works...

Quod erat liberandum.

---------------------------------------
A 4am crack                     No. 595
------------------EOF------------------
